home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
shells
/
zsh-3.0-p
/
zsh-3
/
zsh-3.0-pre3
/
Src
/
zle_refresh.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-15
|
27KB
|
987 lines
/*
* $Id: zle_refresh.c,v 2.6 1996/07/14 18:58:54 hzoli Exp $
*
* zle_refresh.c - screen update
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1992-1996 Paul Falstad
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* In no event shall Paul Falstad or the Zsh Development Group be liable
* to any party for direct, indirect, special, incidental, or consequential
* damages arising out of the use of this software and its documentation,
* even if Paul Falstad and the Zsh Development Group have been advised of
* the possibility of such damage.
*
* Paul Falstad and the Zsh Development Group specifically disclaim any
* warranties, including, but not limited to, the implied warranties of
* merchantability and fitness for a particular purpose. The software
* provided hereunder is on an "as is" basis, and Paul Falstad and the
* Zsh Development Group have no obligation to provide maintenance,
* support, updates, enhancements, or modifications.
*
*/
#define ZLE
#include "zsh.h"
#ifdef HAVE_SELECT
#define SELECT_ADD_COST(X) cost += X
#else
#define SELECT_ADD_COST(X)
#endif
/* Oct/Nov 94: <mason> some code savagely redesigned to fix several bugs -
refreshline() & tc_rightcurs() majorly rewritten; refresh() fixed -
I've put my fingers into just about every routine in here -
any queries about updates to mason@werple.net.au */
char **nbuf = NULL, /* new video buffer line-by-line char array */
**obuf = NULL; /* old video buffer line-by-line char array */
static char *lpptbuf, *rpptbuf; /* prompt buffers */
static int baudrate, /* BAUD */
more_start, /* more text before start of screen? */
more_end, /* more stuff after end of screen? */
olnct, /* previous number of lines */
ovln, /* previous video cursor position line */
lpptlen, rpptlen, /* length of prompt buffers */
pptw, rpw, /* prompt widths on screen */
vcs, vln, /* video cursor position column & line */
vmaxln, /* video maximum number of lines */
winw, winh, /* window width & height */
winpos; /* singlelinezle: line's position in window */
static unsigned pmpt_attr = 0, /* text attributes after displaying prompt */
rpmpt_attr = 0; /* text attributes after displaying rprompt */
/**/
void
resetvideo(void)
{
int ln;
static int lwinw = -1, lwinh = -1; /* last window width & height */
winw = (columns < 1) ? (columns = 80) : columns; /* terminal width */
if (isset(SINGLELINEZLE) || termok != TERM_OK)
winh = 1;
else
winh = (lines < 2) ? 24 : lines;
winpos = vln = vmaxln = 0;
if (lwinw != winw || lwinh != winh) {
if (nbuf) {
for (ln = 0; ln != lwinh; ln++) {
zfree(nbuf[ln], lwinw + 1);
zfree(obuf[ln], lwinw + 1);
}
free(nbuf);
free(obuf);
}
nbuf = (char **)zcalloc((winh + 1) * sizeof(char *));
obuf = (char **)zcalloc((winh + 1) * sizeof(char *));
nbuf[0] = (char *)zalloc(winw + 1);
obuf[0] = (char *)zalloc(winw + 1);
lwinw = winw;
lwinh = winh;
}
for (ln = 0; ln != winh + 1; ln++) {
if (nbuf[ln])
*nbuf[ln] = '\0';
if (obuf[ln])
*obuf[ln] = '\0';
}
if (pptw) {
memset(nbuf[0], ' ', pptw);
memset(obuf[0], ' ', pptw);
nbuf[0][pptw] = obuf[0][pptw] = '\0';
}
vcs = pptw;
olnct = nlnct = 0;
if (showinglist > 0)
showinglist = -2;
}
/*
* Jul 96: changed to single line scroll for higher speed terminals - mason
* I've seperated the loops for readability (and it's slightly faster)
* Returns line number to be used next
*/
/**/
int
scrollwindow(int tline)
{
int t0, hwinh;
char *s;
if (tline || baudrate >= 9600) { /* single line scroll */
hwinh = 1;
s = nbuf[tline];
for (t0 = tline; t0 < winh - 1; t0++)
nbuf[t0] = nbuf[t0 + 1];
nbuf[winh - 1] = s;
} else { /* half screen scroll */
hwinh = winh / 2;
for (t0 = 0; t0 != winh - hwinh; t0++) {
s = nbuf[t0];
nbuf[t0] = nbuf[t0 + hwinh];
nbuf[t0 + hwinh] = s;
}
}
if (!tline)
more_start = 1;
return winh - hwinh;
}
/* this is the messy part. */
/* this define belongs where it's used!!! */
#define nextline \
{ \
*s = '\0'; \
if (++ln == winh) \
if (nvln != -1) { \
ln--; /* too eager */ \
break; \
} else \
ln = scrollwindow(0); \
if (!nbuf[ln]) \
nbuf[ln] = (char *)zalloc(winw + 1); \
s = (unsigned char *)nbuf[ln]; \
sen = s + winw; \
}
#define snextline \
{ \
*s = '\0'; \
if (++ln == winh) \
if (tosln <= nvln + 1) { \
ln = scrollwindow(0); \
if (nvln) \
nvln--, tosln--; \
} else { \
tosln--; \
ln = scrollwindow(tosln); \
} \
if (!nbuf[ln]) \
nbuf[ln] = (char *)zalloc(winw + 1); \
s = (unsigned char *)nbuf[ln]; \
sen = s + winw; \
}
#ifdef TIOCGWINSZ
int winchanged; /* window size changed */
#endif
int cleareol, /* clear to end-of-line (if can't cleareod) */
clearf = 0, /* alwayslastprompt used immediately before */
hasam; /* terminal should have auto-margin */
static int put_rpmpt, /* whether we should display right-prompt */
oput_rpmpt; /* whether displayed right-prompt last time */
extern int clearflag; /* set to non-zero if alwayslastprompt used */
/**/
void
refresh(void)
{
static int inlist; /* avoiding recursion */
int ln = 0, /* current line we're working on */
nvcs = 0, nvln = -1, /* video cursor column and line */
t0 = -1, /* tmp */
tosln; /* tmp in statusline stuff */
unsigned char *s, /* pointer into the video buffer */
*t, /* pointer into the real buffer */
*sen, /* pointer to end of the video buffer (eol) */
*scs; /* pointer to cursor position in real buffer */
char **qbuf; /* tmp */
/* If this is called from listmatches() (indirectly via trashzle()), and *
* that was called from the end of refresh(), then we don't need to do *
* anything. All this `inlist' code is actually unnecessary, but it *
* improves speed a little in a common case. */
if (inlist)
return;
#ifdef HAVE_SELECT
cost = 0; /* reset */
#endif
cleareol = 0; /* unset */
more_start = more_end = 0; /* unset */
baudrate = getiparam("BAUD");
if (resetneeded) {
setterm();
#ifdef TIOCGWINSZ
if (winchanged) {
moveto(0, 0);
t0 = olnct; /* this is to clear extra lines even when */
winchanged = 0; /* the terminal cannot TCCLEAREOD */
}
#endif
resetvideo();
resetneeded = 0; /* unset */
oput_rpmpt = 0; /* no right-prompt currently on screen */
if (!clearflag)
if (tccan(TCCLEAREOD))
tcout(TCCLEAREOD);
else
cleareol = 1; /* request: clear to end of line */
if (t0 > -1)
olnct = t0;
if (isset(SINGLELINEZLE) || termok != TERM_OK)
vcs = 0;
else if (!clearflag && lpptlen) {
fwrite(lpptbuf, lpptlen, 1, shout);
fflush(shout);
}
if (clearflag) {
putc('\r', shout);
vcs = 0;
moveto(0, pptw);
}
clearf = clearflag;
} else if (winw != columns)
resetvideo();
/* now winw equals columns; now all width comparisons can be made to winw */
if (isset(SINGLELINEZLE) || termok != TERM_OK) {
singlerefresh();
return;
}
if (cs < 0) {
#ifdef DEBUG
fprintf(stderr, "BUG: negative cursor position\n");
fflush(stderr);
#endif
cs = 0;
}
scs = line + cs;
/* first, we generate the video line buffers so we know what to put on
the screen - also determine final cursor position (nvln, nvcs) */
/* Deemed necessary by PWS 1995/05/15 due to kill-line problems */
if (!*nbuf)
*nbuf = (char *)zalloc(winw + 1);
s = (unsigned char *)(nbuf[ln = 0] + pptw);
t = line;
sen = (unsigned char *)(*nbuf + winw);
for (; t < line+ll; t++) {
if (t == scs) /* if cursor is here, remember it */
nvcs = s - (unsigned char *)(nbuf[nvln = ln]);
if (*t == '\n') /* newline */
nextline
else if (*t == '\t') { /* tab */
t0 = (char *)s - nbuf[ln];
if ((t0 | 7) + 1 >= winw)
nextline
else
do
*s++ = ' ';
while ((++t0) & 7);
} else if (icntrl(*t)) { /* other control character */
*s++ = '^';
if (s == sen)
nextline
*s++ = (*t == 127) ? '?' : (*t | '@');
} else /* normal character */
*s++ = *t;
if (s == sen)
nextline
}
/* if we're really on the next line, don't fake it; do everything properly */
if (t == scs && (nvcs = s - (unsigned char *)(nbuf[nvln = ln])) == winw) {
*s = '\0';
if (!nbuf[++ln])
nbuf[ln] = (char *)zalloc(winw + 1);
s = (unsigned char *)nbuf[ln];
nvcs = 0;
nvln++;
}
if (t != line + ll)
more_end = 1;
if (statusline) {
tosln = ln + 1;
snextline
t = (unsigned char *)statusline;
for (; t < (unsigned char *)statusline+statusll; t++) {
if (icntrl(*t)) { /* simplified processing in the status line */
*s++ = '^';
if (s == sen)
snextline
*s++ = (*t == 127) ? '?' : (*t | '@');
} else
*s++ = *t;
if (s == sen)
snextline
}
}
/* insert <.... at end of last line if there is more text past end of screen */
if (more_end) {
if (!statusline)
tosln = winh;
strncpy(nbuf[tosln - 1] + winw - 7, " <.... ", 7);
nbuf[tosln - 1][winw] = '\0';
}
*s = '\0';
nlnct = ln + 1;
for (ln = nlnct; ln < winh; ln++)
zfree(nbuf[ln], winw + 1), nbuf[ln] = NULL;
/* determine whether the right-prompt exists and can fit on the screen */
if (!more_start)
put_rpmpt = rpptlen && (int)strlen(nbuf[0]) + rpw < winw - 1;
else {
/* insert >.... on first line if there is more text before start of screen */
memset(nbuf[0], ' ', pptw);
t0 = winw - pptw;
t0 = t0 > 5 ? 5 : t0;
strncpy(nbuf[0] + pptw, ">....", t0);
memset(nbuf[0] + pptw + t0, ' ', winw - t0 - pptw);
nbuf[0][winw] = '\0';
}
for (ln = 0; !clearf && (ln < nlnct); ln++) {
/* if we have more lines than last time, clear the newly-used lines */
if (ln >= olnct)
cleareol = 1;
/* if old line and new line are different,
see if we can insert/delete a line to speed up update */
if (ln < olnct - 1 && !(hasam && vcs == winw) &&
nbuf[ln] && obuf[ln] &&
strncmp(nbuf[ln], obuf[ln], 16)) {
if (tccan(TCDELLINE) && obuf[ln + 1] && obuf[ln + 1][0] &&
nbuf[ln] && !strncmp(nbuf[ln], obuf[ln + 1], 16)) {
moveto(ln, 0);
tcout(TCDELLINE);
zfree(obuf[ln], winw + 1);
for (t0 = ln; t0 != olnct; t0++)
obuf[t0] = obuf[t0 + 1];
obuf[--olnct] = NULL;
}
/* don't try to insert a line if olnct = vmaxln (vmaxln is the number
of lines that have been displayed by this routine) so that we don't
go off the end of the screen. */
else if (tccan(TCINSLINE) && olnct < vmaxln && nbuf[ln + 1] &&
obuf[ln] && !strncmp(nbuf[ln + 1], obuf[ln], 16)) {
moveto(ln, 0);
tcout(TCINSLINE);
for (t0 = olnct; t0 != ln; t0--)
obuf[t0] = obuf[t0 - 1];
obuf[ln] = NULL;
olnct++;
}
}
/* update the single line */
refreshline(ln);
/* output the right-prompt if appropriate */
if (put_rpmpt && !ln && !oput_rpmpt) {
moveto(0, winw - 1 - rpw);
fwrite(rpptbuf, rpptlen, 1, shout);
vcs = winw - 1;
/* reset character attributes to that set by the main prompt */
txtchange = pmpt_attr;
if (txtchangeisset(TXTNOBOLDFACE) && (rpmpt_attr & TXTBOLDFACE))
tsetcap(TCALLATTRSOFF, 0);
if (txtchangeisset(TXTNOSTANDOUT) && (rpmpt_attr & TXTSTANDOUT))
tsetcap(TCSTANDOUTEND, 0);
if (txtchangeisset(TXTNOUNDERLINE) && (rpmpt_attr & TXTUNDERLINE))
tsetcap(TCUNDERLINEEND, 0);
if (txtchangeisset(TXTBOLDFACE) && (rpmpt_attr & TXTNOBOLDFACE))
tsetcap(TCBOLDFACEBEG, 0);
if (txtchangeisset(TXTSTANDOUT) && (rpmpt_attr & TXTNOSTANDOUT))
tsetcap(TCSTANDOUTBEG, 0);
if (txtchangeisset(TXTUNDERLINE) && (rpmpt_attr & TXTNOUNDERLINE))
tsetcap(TCUNDERLINEBEG, 0);
}
}
/* if old buffer had extra lines, set them to be cleared and refresh them
individually */
if (olnct > nlnct) {
cleareol = 1;
for (ln = nlnct; ln < olnct; ln++)
refreshline(ln);
}
/* reset character attributes */
if (clearf && postedit) {
if ((txtchange = pmpt_attr ? pmpt_attr : rpmpt_attr)) {
if (txtchangeisset(TXTNOBOLDFACE))
tsetcap(TCALLATTRSOFF, 0);
if (txtchangeisset(TXTNOSTANDOUT))
tsetcap(TCSTANDOUTEND, 0);
if (txtchangeisset(TXTNOUNDERLINE))
tsetcap(TCUNDERLINEEND, 0);
if (txtchangeisset(TXTBOLDFACE))
tsetcap(TCBOLDFACEBEG, 0);
if (txtchangeisset(TXTSTANDOUT))
tsetcap(TCSTANDOUTBEG, 0);
if (txtchangeisset(TXTUNDERLINE))
tsetcap(TCUNDERLINEBEG, 0);
}
}
clearf = 0;
/* move to the new cursor position */
moveto(nvln, nvcs);
/* swap old and new buffers - better than freeing/allocating every time */
qbuf = nbuf;
nbuf = obuf;
obuf = qbuf;
/* store current values so we can use them next time */
ovln = nvln;
olnct = nlnct;
oput_rpmpt = put_rpmpt;
if (nlnct > vmaxln)
vmaxln = nlnct;
fflush(shout); /* make sure everything is written out */
/* if we have a new list showing, note it; if part of the list has been
overwritten, redisplay it. */
if (showinglist == -2 || (showinglist > 0 && showinglist < nlnct)) {
inlist = 1;
listmatches();
inlist = 0;
refresh();
}
if (showinglist == -1)
showinglist = nlnct;
}
#define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
#define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL])
#define tc_delchars(X) (void) tcmultout(TCDEL, TCMULTDEL, (X))
#define tc_inschars(X) (void) tcmultout(TCINS, TCMULTINS, (X))
#define tc_upcurs(X) (void) tcmultout(TCUP, TCMULTUP, (X))
#define tc_leftcurs(X) (void) tcmultout(TCLEFT, TCMULTLEFT, (X))
/* refresh one line, using whatever speed-up tricks are provided by the tty */
/**/
void
refreshline(int ln)
{
char *nl, *ol, *p1; /* line buffer pointers */
int ccs = 0, /* temporary count for cursor position */
char_ins = 0, /* number of characters inserted/deleted */
col_cleareol, /* clear to end-of-line from this column */
i, j, /* tmp */
nllen, ollen; /* new and old line buffer lengths */
/* 0: setup */
nl = nbuf[ln];
nllen = nl ? strlen(nl) : 0;
ol = obuf[ln] ? obuf[ln] : "";
ollen = strlen(ol);
/* 1: pad out the new buffer with spaces to contain _all_ of the characters
which need to be written. do this now to allow some pre-processing */
if (cleareol /* request to clear to end of line */
|| !nllen /* no line buffer given */
|| (ln == 0 && (put_rpmpt != oput_rpmpt))) { /* prompt changed */
p1 = halloc(winw + 1);
if (nllen)
strncpy(p1, nl, nllen);
memset(p1 + nllen, ' ', winw - nllen);
p1[winw] = '\0';
if (ln && nbuf[ln])
strncpy(nl, p1, winw + 1); /* next time obuf will be up-to-date */
else
nl = p1; /* shouldn't happen */
nllen = winw;
} else if (ollen > nllen) { /* make new line at least as long as old */
p1 = halloc(ollen + 1);
strncpy(p1, nl, nllen);
memset(p1 + nllen, ' ', ollen - nllen);
p1[ollen] = '\0';
nl = p1;
nllen = ollen;
}
/* 2: see if we can clear to end-of-line, and if it's faster, work out where
to do it from - we can normally only do so if there's no right-prompt.
With automatic margins, we shouldn't do it if there is another line, in
case it messes up cut and paste. */
if (hasam && ln < nlnct - 1)
col_cleareol = -2; /* clearing eol would be evil so don't */
else {
col_cleareol = -1;
if (tccan(TCCLEAREOL) && (nllen == winw || put_rpmpt != oput_rpmpt)) {
for (i = nllen; i && nl[i - 1] == ' '; i--);
for (j = ollen; j && ol[j - 1] == ' '; j--);
if ((j > i + tclen[TCCLEAREOL]) /* new buf has enough spaces */
|| (nllen == winw && nl[winw - 1] == ' '))
col_cleareol = i;
}
}
/* 3: main display loop - write out the buffer using whatever tricks we can */
for (;;) {
/* skip past all matching characters */
for (; *nl && (*nl == *ol); nl++, ol++, ccs++) ;
if (!*nl) {
if ((char_ins <= 0) || (ccs >= winw)) /* written everything */
return;
else /* we've got junk on the right yet to clear */
if (tccan(TCCLEAREOL) && (char_ins >= tclen[TCCLEAREOL])
&& col_cleareol != -2)
col_cleareol = 0; /* force a clear to end of line */
}
moveto(ln, ccs); /* move to where we do all output from */
/* if we can finish quickly, do so */
if ((col_cleareol >= 0) && (ccs >= col_cleareol)) {
tcout(TCCLEAREOL);
SELECT_ADD_COST(tclen[TCCLEAREOL]);
return;
}
/* we've written out the new but yet to clear rubbish due to inserts */
if (!*nl) {
i = (winw - ccs < char_ins) ? (winw - ccs) : char_ins;
if (tccan(TCDEL) && (tcdelcost(i) <= i + 1))
tc_delchars(i);
else {
SELECT_ADD_COST(i);
vcs += i;
while (i-- > 0)
putc(' ', shout);
}
return;
}
/* if we've reached the end of the old buffer, then there are few tricks
we can do, so we just dump out what we must and clear if we can */
if (!*ol) {
i = (col_cleareol >= 0) ? col_cleareol : nllen;
i -= ccs;
fwrite(nl, i, 1, shout);
SELECT_ADD_COST(i);
vcs += i;
if (col_cleareol >= 0) {
tcout(TCCLEAREOL);
SELECT_ADD_COST(tclen[TCCLEAREOL]);
}
return;
}
/* inserting & deleting chars: we can if there's no right-prompt */
if ((ln || !put_rpmpt || !oput_rpmpt)) {
/* deleting characters - see if we can find a match series that
makes it cheaper to delete intermediate characters
eg. oldline: hifoobar } hopefully cheaper here to delete two
newline: foobar } characters, then we have six matches */
if (tccan(TCDEL) && nl[1] && ol[1] && (ol[1] != nl[1])) {
for (i = 0, p1 = ol; *p1; p1++, i++)
if (tcdelcost(i) < pfxlen(p1, nl)) {
tc_delchars(i);
SELECT_ADD_COST(i);
ol = p1;
char_ins -= i;
break;
}
if (*p1)
continue;
}
/* inserting characters - characters pushed off the right should be
annihilated, but we don't do this if we're on the last line lest
undesired scrolling occurs due to `illegal' characters on screen */
if ((vln != lines - 1) && /* not on last line */
tccan(TCINS) && nl[1] && ol[1] && (ol[1] != nl[1])) {
for (i = 0, p1 = nl; *p1; p1++, i++)
if (tcinscost(i) < pfxlen(p1, ol)) {
tc_inschars(i);
SELECT_ADD_COST(2 * i);
fwrite(nl, i, 1, shout);
ccs = (vcs += i);
nl = p1;
char_ins += i;
break;
}
if (*p1)
continue;
}
}
/* we can't do any fancy tricks, so just dump the single character
and keep on trying */
putc(*nl, shout);
SELECT_ADD_COST(1);
nl++, ol++;
ccs++, vcs++;
}
}
/* move the cursor to line ln (relative to the prompt line),
absolute column cl; update vln, vcs - video line and column */
/**/
void
moveto(int ln, int cl)
{
if (vcs == winw) {
vln++, vcs = 0;
if (!hasam) {
putc('\r', shout);
putc('\n', shout);
} else {
if ((vln < nlnct) && nbuf[vln] && *nbuf[vln])
putc(*nbuf[vln], shout);
else
putc(' ', shout);
putc('\r', shout);
if ((vln < olnct) && obuf[vln] && *obuf[vln])
*obuf[vln] = *nbuf[vln];
}
SELECT_ADD_COST(2);
}
if (ln == vln && cl == vcs)
return;
/* move up */
if (ln < vln) {
tc_upcurs(vln - ln);
vln = ln;
}
/* move down; if we might go off the end of the screen, use newlines
instead of TCDOWN */
while (ln > vln) {
if (vln < vmaxln - 1)
if (ln > vmaxln - 1) {
if (tc_downcurs(vmaxln - 1 - vln))
vcs = 0;
vln = vmaxln - 1;
} else {
if (tc_downcurs(ln - vln))
vcs = 0;
vln = ln;
continue;
}
putc('\r', shout), vcs = 0; /* safety precaution */
SELECT_ADD_COST(1);
while (ln > vln) {
putc('\n', shout);
SELECT_ADD_COST(1);
vln++;
}
}
if (cl == vcs)
return;
/* choose cheapest movements for ttys without multiple movement capabilities -
do this now because it's easier (to code) */
if (cl <= vcs / 2) {
putc('\r', shout);
SELECT_ADD_COST(1);
vcs = 0;
}
if (vcs < cl)
tc_rightcurs(cl);
else if (vcs > cl)
tc_leftcurs(vcs - cl);
vcs = cl;
}
/**/
int
tcmultout(int cap, int multcap, int ct)
{
if (tccan(multcap) && (!tccan(cap) || tclen[multcap] < tclen[cap] * ct)) {
tcoutarg(multcap, ct);
SELECT_ADD_COST(tclen[multcap]);
return 1;
} else if (tccan(cap)) {
SELECT_ADD_COST((tclen[cap] * ct));
while (ct--)
tcout(cap);
return 1;
}
return 0;
}
/**/
void
tc_rightcurs(int cl)
{
int ct = cl - vcs, /* number of characters to move across */
horz_tabs = 0, /* number of horizontal tabs if we do them */
i = vcs, /* cursor position after initial movements */
j = 0; /* number of chars outputted if we use tabs */
char *t;
/* calculate how many horizontal tabs it would take, if we can do them -
tabs are assumed to be 8 spaces */
if (tccan(TCNEXTTAB) && ((vcs | 7) < cl)) {
horz_tabs = 1;
i = (vcs | 7) + 1;
for (; i + 8 <= cl; i += 8)
horz_tabs++;
j = cl - i; /* number of chars after last tab */
if (tccan(TCRIGHT))
j *= tclen[TCRIGHT];
j += (horz_tabs * tclen[TCNEXTTAB]); /* # of chars if we use tabs */
}
/* do a multright if we can - if it's cheaper or we can't use other tricks */
if (tccan(TCMULTRIGHT) &&
(!tccan(TCRIGHT) || (tclen[TCMULTRIGHT] < tclen[TCRIGHT] * ct) ||
!tccan(TCNEXTTAB) || (tclen[TCMULTRIGHT] < j))) {
tcoutarg(TCMULTRIGHT, ct);
SELECT_ADD_COST(tclen[TCMULTRIGHT]);
return;
}
/* try to go with tabs if a multright is not feasible/convenient */
if (horz_tabs) {
SELECT_ADD_COST((tclen[TCNEXTTAB] * horz_tabs));
for (; horz_tabs--;)
tcout(TCNEXTTAB);
if ((ct = cl - i) == 0) /* number of chars still to move across */
return;
}
/* or try to dump lots of right movements */
if (tccan(TCRIGHT)) {
SELECT_ADD_COST((tclen[TCRIGHT] * ct));
for (; ct--;)
tcout(TCRIGHT);
return;
}
/* otherwise _carefully_ write the contents of the video buffer */
SELECT_ADD_COST(ct);
for (j = 0, t = nbuf[vln]; *t && (j < i); j++, t++);
if (j == i)
for ( ; *t && ct; ct--, t++)
putc(*t, shout);
while (ct--)
putc(' ', shout); /* not my fault your terminal can't go right */
}
/**/
int
tc_downcurs(int ct)
{
int ret = 0;
if (ct && !tcmultout(TCDOWN, TCMULTDOWN, ct)) {
SELECT_ADD_COST(ct + 1);
while (ct--)
putc('\n', shout);
putc('\r', shout), ret = -1;
}
return ret;
}
/**/
void
tcout(int cap)
{
tputs(tcstr[cap], 1, putshout);
}
/**/
void
tcoutarg(int cap, int arg)
{
tputs(tgoto(tcstr[cap], arg, arg), 1, putshout);
}
/**/
void
clearscreen(void)
{
tcout(TCCLEARSCREEN);
resetneeded = 1;
clearflag = 0;
}
/**/
void
redisplay(void)
{
moveto(0, pptw);
putc('\r', shout);
resetneeded = 1;
clearflag = 0;
}
/**/
void
singlerefresh(void)
{
char *vbuf, *vp, /* video buffer and pointer */
**qbuf, /* tmp */
*refreshop = *obuf; /* pointer to old video buffer */
int t0, /* tmp */
vsiz, /* size of new video buffer */
nvcs = 0; /* new video cursor column */
nlnct = 1;
/* generate the new line buffer completely */
for (vsiz = 1 + pptw, t0 = 0; t0 != ll; t0++, vsiz++)
if (line[t0] == '\t')
vsiz = (vsiz | 7) + 1;
else if (icntrl(line[t0]))
vsiz++;
vbuf = (char *)zalloc(vsiz);
if (cs < 0) {
#ifdef DEBUG
fprintf(stderr, "BUG: negative cursor position\n");
fflush(stderr);
#endif
cs = 0;
}
memcpy(vbuf, lpptbuf + lpptlen - pptw, pptw); /* only use last part of prompt */
vbuf[pptw] = '\0';
vp = vbuf + pptw;
for (t0 = 0; t0 != ll; t0++) {
if (line[t0] == '\t')
for (*vp++ = ' '; (vp - vbuf) & 7; )
*vp++ = ' ';
else if (line[t0] == '\n') {
*vp++ = '\\';
*vp++ = 'n';
} else if (line[t0] == 0x7f) {
*vp++ = '^';
*vp++ = '?';
} else if (icntrl(line[t0])) {
*vp++ = '^';
*vp++ = line[t0] | '@';
} else
*vp++ = line[t0];
if (t0 == cs)
nvcs = vp - vbuf - 1;
}
if (t0 == cs)
nvcs = vp - vbuf;
*vp = '\0';
/* determine which part of the new line buffer we want for the display */
if ((winpos && nvcs < winpos + 1) || (nvcs > winpos + winw - 2)) {
if ((winpos = nvcs - ((winw - hasam) / 2)) < 0)
winpos = 0;
}
if (winpos)
vbuf[winpos] = '<'; /* line continues to the left */
if ((int)strlen(vbuf + winpos) > (winw - hasam)) {
vbuf[winpos + winw - hasam - 1] = '>'; /* line continues to right */
vbuf[winpos + winw - hasam] = '\0';
}
strcpy(nbuf[0], vbuf + winpos);
zfree(vbuf, vsiz);
nvcs -= winpos;
/* display the `visable' portion of the line buffer */
for (t0 = 0, vp = *nbuf;;) {
/* skip past all matching characters */
for (; *vp && *vp == *refreshop; t0++, vp++, refreshop++) ;
if (!*vp && !*refreshop)
break;
singmoveto(t0); /* move to where we do all output from */
if (!*refreshop) {
if ((t0 = strlen(vp)))
fwrite(vp, t0, 1, shout);
vcs += t0;
break;
}
if (!*vp) {
if (tccan(TCCLEAREOL))
tcout(TCCLEAREOL);
else
for (; *refreshop++; vcs++)
putc(' ', shout);
break;
}
putc(*vp, shout);
vcs++, t0++;
vp++, refreshop++;
}
/* move to the new cursor position */
singmoveto(nvcs);
qbuf = nbuf;
nbuf = obuf;
obuf = qbuf;
fflush(shout); /* make sure everything is written out */
}
/**/
void
singmoveto(int pos)
{
if (pos == vcs)
return;
if (pos <= vcs / 2) {
putc('\r', shout);
vcs = 0;
}
if (pos < vcs) {
tc_leftcurs(vcs - pos);
vcs = pos;
}
if (pos > vcs) {
if (tcmultout(TCRIGHT, TCMULTRIGHT, pos - vcs))
vcs = pos;
else
while (pos > vcs) {
putc(nbuf[0][vcs], shout);
vcs++;
}
}
}
/* generate left and right prompts */
/**/
void
genprompts(void)
{
zsfree(lpptbuf);
zsfree(rpptbuf);
lpptbuf = putprompt(lpmpt, &lpptlen, &pptw, 1);
pmpt_attr = txtchange;
rpptbuf = putprompt(rpmpt, &rpptlen, &rpw, 1);
rpmpt_attr = txtchange;
}